{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4fbae0f9",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# VQE Method for Molecule Energy Solver\n",
    "\n",
    "This notebook demonstrates how to use the `construct_chemistry_model` function, which constructs a VQE model for Molecule eigensolver. For more comprehensive explanation on the algorithm see [Molecule Eigensolver notebook](https://github.com/Classiq/classiq-library/blob/main/applications/chemistry/molecule_eigensolver/molecule_eigensolver.ipynb).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c6bbe65f-1e6a-475c-a43f-cb4cc04bbdfa",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:21:05.764048Z",
     "iopub.status.busy": "2024-05-07T13:21:05.763815Z",
     "iopub.status.idle": "2024-05-07T13:21:08.916824Z",
     "shell.execute_reply": "2024-05-07T13:21:08.915990Z"
    },
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from classiq import QuantumProgram, construct_chemistry_model, execute, show, synthesize\n",
    "from classiq.applications.chemistry import (\n",
    "    ChemistryExecutionParameters,\n",
    "    Molecule,\n",
    "    MoleculeProblem,\n",
    "    UCCParameters,\n",
    ")\n",
    "from classiq.execution import (\n",
    "    ClassiqBackendPreferences,\n",
    "    ClassiqSimulatorBackendNames,\n",
    "    ExecutionPreferences,\n",
    "    OptimizerType,\n",
    ")\n",
    "from classiq.synthesis import set_execution_preferences"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "faa3c10f",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 1. Defining a Molecule and a Molecule Problem\n",
    "\n",
    "First, declare the class Molecule and insert a list of atoms and their spacial positions (distances are in \u00c5 ($10^{-10} m$)). Below we treat the $H_2$ example."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ef2ce57e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:21:08.921518Z",
     "iopub.status.busy": "2024-05-07T13:21:08.920520Z",
     "iopub.status.idle": "2024-05-07T13:21:08.927162Z",
     "shell.execute_reply": "2024-05-07T13:21:08.926328Z"
    },
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "molecule_H2 = Molecule(atoms=[(\"H\", (0.0, 0.0, 0)), (\"H\", (0.0, 0.0, 0.735))])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c4a541a5",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Next, we define the parameters of the Hamiltonian generation program. The user has a choice over the following options:\n",
    "- mapping (str): the mapping between the fermionic Hamiltonian and the qubits Hamiltonian. Supported types:\n",
    "        - \"jordan_wigner\"\n",
    "        - \"parity\"\n",
    "        - \"bravyi_kitaev\"\n",
    "        - \"fast_bravyi_kitaev\"\n",
    "- freeze_core (bool): remove the \"core\" orbitals of the atoms defining the molecule.\n",
    "- z2_symmetries (bool): whether to perform z2 symmetries reduction. If symmetries in the molecules exist, this option will decrease the number of qubits defining the Hamiltonian and thus make the calculations more efficient."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2e0426d5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:21:08.932605Z",
     "iopub.status.busy": "2024-05-07T13:21:08.931423Z",
     "iopub.status.idle": "2024-05-07T13:21:08.936781Z",
     "shell.execute_reply": "2024-05-07T13:21:08.936032Z"
    }
   },
   "outputs": [],
   "source": [
    "chemistry_problem = MoleculeProblem(\n",
    "    molecule=molecule_H2,\n",
    "    mapping=\"jordan_wigner\",\n",
    "    z2_symmetries=False,\n",
    "    freeze_core=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8abe3e3d-1b01-4fab-b86a-feaab3851950",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 2. Constructing and Synthesizing a Ground State Solver\n",
    "\n",
    "The quantum part of the model consists of a parameterized quantum function (\"the ansatz\"). The constructor function allows to choose whether to start with an initial Hartree Fock function, and the choice of three built-in variational functions:  Hardware Efficient Ansatz (HEA), Unitary Coupled Cluster ansatz (UCC), and Hamiltonian Variational ansatz (HVA).\n",
    "\n",
    "The classical part of the algorithm runs a classical optimizer for finding the optimal parameters, as well as post-processes the result and returns the total energy (combining the ground state energy of the Hamiltonian, the nuclear repulsion and the static nuclear energy).\n",
    "\n",
    "In the example below we use Hartree Fock initial condition and a UCC ansatz with single and double excitations. For the classical solver we take the `COBYLA` optimizer with \n",
    "up to 30 iterations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1f520673",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:21:08.944061Z",
     "iopub.status.busy": "2024-05-07T13:21:08.940858Z",
     "iopub.status.idle": "2024-05-07T13:21:14.435150Z",
     "shell.execute_reply": "2024-05-07T13:21:14.434419Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opening: https://platform.classiq.io/circuit/fcd44b9e-35b2-4ee9-97e5-c91f32589d1a?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "chemistry_model = construct_chemistry_model(\n",
    "    chemistry_problem=chemistry_problem,\n",
    "    use_hartree_fock=True,\n",
    "    ansatz_parameters=UCCParameters(excitations=[1, 2]),\n",
    "    execution_parameters=ChemistryExecutionParameters(\n",
    "        optimizer=OptimizerType.COBYLA,\n",
    "        max_iteration=30,\n",
    "        initial_point=None,\n",
    "    ),\n",
    ")\n",
    "\n",
    "backend_preferences = ClassiqBackendPreferences(\n",
    "    backend_name=ClassiqSimulatorBackendNames.SIMULATOR\n",
    ")\n",
    "\n",
    "chemistry_model = set_execution_preferences(\n",
    "    chemistry_model,\n",
    "    execution_preferences=ExecutionPreferences(\n",
    "        num_shots=1000, backend_preferences=backend_preferences\n",
    "    ),\n",
    ")\n",
    "\n",
    "qprog = synthesize(chemistry_model)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "bfd18189-3798-4b0c-9e6d-58c739ff078c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:21:14.439866Z",
     "iopub.status.busy": "2024-05-07T13:21:14.438700Z",
     "iopub.status.idle": "2024-05-07T13:21:14.464526Z",
     "shell.execute_reply": "2024-05-07T13:21:14.463766Z"
    }
   },
   "outputs": [],
   "source": [
    "from classiq import write_qmod\n",
    "\n",
    "write_qmod(chemistry_model, \"chemistry\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f12c9a32-f271-4892-8515-bd9e6b9fcf8b",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Classiq's UCC function provides a highly efficient solution in aspects of circuit depth and number of CX gates. Those ultimately reduce the gate's time and amount of resources needed for its operation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef36661f",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 3. Executing to Find the Ground State\n",
    "\n",
    "Once we've synthesized the model we can execute it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1a66d377",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:21:14.469727Z",
     "iopub.status.busy": "2024-05-07T13:21:14.468576Z",
     "iopub.status.idle": "2024-05-07T13:21:21.060624Z",
     "shell.execute_reply": "2024-05-07T13:21:21.059844Z"
    }
   },
   "outputs": [],
   "source": [
    "result = execute(qprog).result()\n",
    "chemistry_result_dict = result[1].value"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f72ceeb5-bc71-46d8-a390-31ec874700f3",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Execution of the quantum program returns the full VQE solution (e.g., the values of the `optimal_parameters`), as well as the post-processed results (e.g., the value of the `total_energy`, which is the ground state energy of the Hamiltonian)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "437b3211",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:21:21.066348Z",
     "iopub.status.busy": "2024-05-07T13:21:21.064666Z",
     "iopub.status.idle": "2024-05-07T13:21:21.078910Z",
     "shell.execute_reply": "2024-05-07T13:21:21.078186Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-1.1367743111939652"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chemistry_result_dict[\"total_energy\"]  # energy is returned in units of Hartree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "9a537d3c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:21:21.083565Z",
     "iopub.status.busy": "2024-05-07T13:21:21.082378Z",
     "iopub.status.idle": "2024-05-07T13:21:21.090261Z",
     "shell.execute_reply": "2024-05-07T13:21:21.089551Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'param_0': -4.6539276399379945,\n",
       " 'param_1': -1.5597296169566757,\n",
       " 'param_2': -4.819846630440713}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chemistry_result_dict[\"vqe_result\"][\"optimal_parameters\"]"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
